//
//  DODBObjectManager.m
//  DOFramework
//
//  Created by 鞠 文杰 on 14-5-13.
//  Copyright (c) 2014年 dono. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "DODBManager.h"

#import "NSDictionary+KeyExtend.h"
#import "DODBObject.h"

#import "DBMetaInfo.h"


@implementation DODBManager{
    NSMutableSet *registedClass;
    NSMutableDictionary *classPropertiesMap;
    NSInteger version;
    NSString *dbPath;
    NSFileManager *fileMgr;
    sqlite3 *database;
    
    //管理所有对象的实例
    NSMutableDictionary *classInfo;
    
    //管理表的主键值
    NSMutableDictionary *pkInfo;
    /**
     @{@"classname",
        @{
            @"insert",@"",
            @"create",@"",
            @"delete",@"",
            @"query",@"",
            @"keyTypes",@{},
            @"dbTypes",@{}
        }
     }
     **/
    NSMutableArray *tables;
}

@synthesize dbPath;

+ (DODBManager*)sharedSingleton
{
    static dispatch_once_t pred;
    static DODBManager *instance=nil;
    
    dispatch_once(&pred,^{
        instance=[[self alloc] initSelf];
    });
    return instance;
}


- (sqlite3*)database
{
    static BOOL first = YES;
    if (first || database == NULL) {
        if (!dbPath) {
            dbPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"database.db"];
            if (![fileMgr fileExistsAtPath:dbPath]) {
                [fileMgr createFileAtPath:dbPath contents:nil attributes:nil];
            }
        }
        first = NO;
        if (sqlite3_open([dbPath UTF8String], &database) != SQLITE_OK) {
            NSAssert(NO, @"打开数据库失败");
            sqlite3_close(database);
        }
        [self checkDBMetaInfo];
        //create some table about database and util table
//
    }
    return database;
}

- (id)init
{
    NSAssert(NO, @"不能通过init方法创建单例对象");
    return nil;
}

- (id) initSelf
{
    self = [super init];
    if(self){
        //gerVersion from table
//        dbPath = dbFilePath;
        registedClass = [NSMutableSet new];
        fileMgr = [NSFileManager defaultManager];
        classPropertiesMap = [NSMutableDictionary new];
        
        tables = [NSMutableArray array];
        classInfo = [NSMutableDictionary dictionary];
        pkInfo = [NSMutableDictionary dictionary];
        
        [self registNotification];

    }
    return self;
}

- (void)setVersion:(int)newVersion
{
    if (newVersion > version) {
        version = newVersion;
        //execute some code
        if (!self.upgrade) {
            version = newVersion;
        }
        else if (self.upgrade()) {
            version = newVersion;
            NSAssert(NO, @"升级失败");
        }
        ;
    }else if(newVersion == version){
        //do Nothing
    }else{
        NSString *errMsg = [NSString stringWithFormat:@"目前数据库版本:%d 小于设置版本号:%d",version,newVersion];
        NSAssert(NO,errMsg);
    }
}

- (void)setVersion:(DBMetaInfo *)versionInfo
     withOperation:(UpgradeBlock)upgrade
{
    if (versionInfo.version > version) {
        //execute some code
        if (upgrade && upgrade()) {
            version = versionInfo.version;
            [versionInfo save];
        }
    }else if(versionInfo.version == version){
        //do Nothing
    }else{
        NSString *errMsg = [NSString stringWithFormat:@"目前数据库版本:%d 小于设置版本号:%d",version,versionInfo.version];
        NSAssert(NO,errMsg);
    }
}

- (NSInteger)currentVersion
{
    return version;
}

- (void)registerInMemory:(Class)clazz properties:(NSDictionary*)properties;
{
    @synchronized(self)
    {
        if(![registedClass containsObject:clazz])
        {
            [registedClass addObject:clazz];
            [classPropertiesMap setValue:properties forKey:[NSString stringWithUTF8String:object_getClassName(clazz)]];
        }
    }
    
}

- (NSDictionary*)getClassProperties:(Class)clazz
{
    if ([registedClass containsObject:NSStringFromClass(clazz)]) {
        return [classPropertiesMap objectForKey:NSStringFromClass(clazz)];
    }else{
        return nil;
    }
}

//检查数据库版本元信息
- (void)checkDBMetaInfo
{

    if([DBMetaInfo allObjects].count<=0){
        DBMetaInfo *initMetaInfo = [[DBMetaInfo alloc] init];
        initMetaInfo.version = 1;
        initMetaInfo.desc = @"初始化1版本";
        [initMetaInfo save];
    }else{
        //读取数据库中的最新版本
        version = [DBMetaInfo QueryHighestVersionRecord];
    }
}

+ (BOOL)existsClassInfo:(Class)clazz
{
    return [[self sharedSingleton] doExistsClassInfo:clazz];
}

- (BOOL)doExistsClassInfo:(Class)clazz
{
    return [tables containsObject:clazz];
}

+ (void)registInMemoryWithClass:(Class)clazz info:(NSMutableDictionary *)info
{
    [[self sharedSingleton] doRegistInMemoryWithClass:clazz info:info];
}

- (void)doRegistInMemoryWithClass:(Class)clazz
                       info:(NSMutableDictionary *)info
{
    //防止更新多次插入
    if (![tables containsObject:clazz]) {
        [tables addObject:clazz];
    }
    
    [classInfo setObject:info forKey:NSStringFromClass(clazz)];
}


+ (NSDictionary*)infoWithClass:(Class)class
{
    return [[self sharedSingleton] doInfoWithClass:class];
}

- (NSDictionary*)doInfoWithClass:(Class)class
{
    return [classInfo objectForKey:NSStringFromClass(class)];
}


+ (NSInteger)primaryKeyWithClass:(NSString *)classname
{
    return [[self sharedSingleton] primaryKeyWithClass:classname];
    
}

- (NSInteger)primaryKeyWithClass:(NSString *)classname
{
    @synchronized(pkInfo)
    {
        if (![pkInfo hasKey:classname]) {
            Class clazz = NSClassFromString(classname);
            if ([clazz isSubclassOfClass:[DODBObject class]]) {
                [pkInfo setObject:[NSNumber numberWithInteger:[clazz pkIndexFromDB]] forKey:classname];
            }
            
        }
        NSInteger index = [[pkInfo objectForKey:classname] integerValue];
        [pkInfo setObject:[NSNumber numberWithInteger:index+1] forKey:classname];
        return index;
    }
}

- (void)registNotification
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(persistPkInfo:) name:UIApplicationWillTerminateNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(persistPkInfo:) name:UIApplicationDidEnterBackgroundNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(loadPkInfo:) name:UIApplicationDidBecomeActiveNotification object:nil];
}

- (void)persistPkInfo:(NSNotification *)notification
{
    NSLog(@"persistPkInfo");
    NSArray *classnameCollection = pkInfo.allKeys;
    for (NSString *classname in classnameCollection) {
        Class clazz = NSClassFromString(classname);
        if ([clazz isSubclassOfClass:[DODBObject class]]) {
            [clazz syncPkIndexToDB:[[pkInfo objectForKey:classname] integerValue]];
        }else{
            [pkInfo removeObjectForKey:classname];
        }
    }
}

- (void)loadPkInfo:(NSNotification *)notification
{
    NSLog(@"loadPkInfo");
    NSArray *classnameCollection = pkInfo.allKeys;
    for (NSString *classname in classnameCollection) {
        Class clazz = NSClassFromString(classname);
        if ([clazz isSubclassOfClass:[DODBObject class]]) {
            [pkInfo setObject:[NSNumber numberWithInteger:[clazz pkIndexFromDB]] forKey:classname];
        }else{
            [pkInfo removeObjectForKey:classname];
        }
    }
}

@end


